a tool for shared writing and social publishing
1import { z } from "zod";
2import { makeRoute } from "../lib";
3import type { Env } from "./route";
4import { idResolver } from "app/(home-pages)/reader/idResolver";
5import { supabaseServerClient } from "supabase/serverClient";
6import { Agent } from "@atproto/api";
7import { getIdentityData } from "actions/getIdentityData";
8import { createOauthClient } from "src/atproto-oauth";
9import {
10 normalizePublicationRow,
11 hasValidPublication,
12} from "src/utils/normalizeRecords";
13import { deduplicateByUri } from "src/utils/deduplicateRecords";
14
15export type GetProfileDataReturnType = Awaited<
16 ReturnType<(typeof get_profile_data)["handler"]>
17>;
18
19export const get_profile_data = makeRoute({
20 route: "get_profile_data",
21 input: z.object({
22 didOrHandle: z.string(),
23 }),
24 handler: async ({ didOrHandle }, { supabase }: Pick<Env, "supabase">) => {
25 // Resolve handle to DID if necessary
26 let did = didOrHandle;
27
28 if (!didOrHandle.startsWith("did:")) {
29 const resolved = await idResolver.handle.resolve(didOrHandle);
30 if (!resolved) {
31 throw new Error("Could not resolve handle to DID");
32 }
33 did = resolved;
34 }
35 let agent;
36 let authed_identity = await getIdentityData();
37 if (authed_identity?.atp_did) {
38 try {
39 const oauthClient = await createOauthClient();
40 let credentialSession = await oauthClient.restore(
41 authed_identity.atp_did,
42 );
43 agent = new Agent(credentialSession);
44 } catch (e) {
45 agent = new Agent({
46 service: "https://public.api.bsky.app",
47 });
48 }
49 } else {
50 agent = new Agent({
51 service: "https://public.api.bsky.app",
52 });
53 }
54
55 let profileReq = agent.app.bsky.actor.getProfile({ actor: did });
56
57 let publicationsReq = supabase
58 .from("publications")
59 .select("*")
60 .eq("identity_did", did);
61
62 let [{ data: profile }, { data: rawPublications }] = await Promise.all([
63 profileReq,
64 publicationsReq,
65 ]);
66
67 // Deduplicate records that may exist under both pub.leaflet and site.standard namespaces
68 const publications = deduplicateByUri(rawPublications || []);
69
70 // Normalize publication records before returning
71 const normalizedPublications = publications
72 .map(normalizePublicationRow)
73 .filter(hasValidPublication);
74
75 return {
76 result: {
77 profile,
78 publications: normalizedPublications,
79 },
80 };
81 },
82});